package com.java.demo.thread;

import java.util.ArrayList;
import java.util.List;

/**
 * @auther zhangwj
 * @date 2020/8/14 10:48 上午
 */
public class Demo {
    public static void main(String[] args) {
        Allocator actr = new Allocator();
        Account account1 = new Account(300, actr);
        Account account2 = new Account(300, actr);
        for (int i = 0; i < 40; i++) {
            new Thread(() -> {
                account1.transfer(5, account2);
                account1.getMoney();
                System.out.println("------------------------");
            }).start();
            new Thread(() -> {
                account2.transfer(5, account1);
                account2.getMoney();
                System.out.println("------------------------");
            }).start();
        }
    }
}

class Allocator {

    private List<Object> als = new ArrayList<>(2);

    public synchronized boolean apply(Object from, Object to) {
        if (als.contains(from) || als.contains(to)) {
            return false;
        } else {
            als.add(from);
            als.add(to);
        }
        return true;
    }

    synchronized void free(Object from, Object to) {
        als.remove(from);
        als.remove(to);
    }

}

class Account {

    private volatile int money;
    private Allocator actr;

    Account(int money, Allocator actr) {
        this.money = money;
        this.actr = actr;
    }

    /**
     * 取款
     *
     * @param money 金额
     */
    public void transfer(int money, Account account) {
        while (!actr.apply(this, account))
            ;
        synchronized (this) {
            synchronized (account) {
                if (money > this.money) {
                    outMsg("转账金额过大");
                    return;
                }
                this.money -= money;
                account.money += money;
            }
        }
        actr.free(this, account);
    }

    public void getMoney() {
        synchronized (this) {
            outMsg("余额:" + this.money);
        }
    }

    public void outMsg(String msg) {
        System.out.println("线程ID:" + Thread.currentThread().getId() + "---线程名称:" + Thread.currentThread().getName() + "---" + msg);
    }
}